﻿/****************
* Authored by Zhuo "Wizcas" Chen
* 2018 © Wubi.fun all rights reserved
*****************/

using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using Wubi.Utils;

public class World : MonoBehaviour
{
    static World _instance;
    public static World instance { get { return _instance ?? (_instance = FindObjectOfType<World>()); } }
    [SerializeField] BlockStack _stackPrefab;

    #region Stack Management

    BlockStack[,] _stacks = new BlockStack[0, 0];
    int colCount { get { return _stacks.GetLength(0); } }
    int rowCount { get { return _stacks.GetLength(1); } }
    Dictionary<string, int> _aliveBlockIds = new Dictionary<string, int>();

    public void SetDimension(Vector2Int dimensions)
    {
        _stacks = new BlockStack[dimensions.x, dimensions.y];
    }

    public void Clear()
    {
        if (_stacks == null) return;
        for (int r = 0; r < rowCount; r++)
        {
            for (int c = 0; c < colCount; c++)
            {
                var stack = _stacks[c, r];
                if (stack != null) stack.Clear();
            }
        }
        _aliveBlockIds.Clear();
        Block.__spawnedBlocks.ForEach(b =>
        {
            if (b != null) Destroy(b.gameObject);
        });
        Block.__spawnedBlocks.Clear();
    }

    bool IsValidCoord(Vector2Int coord)
    {
        var ret = coord.x >= 0 && coord.y >= 0 && coord.x < colCount && coord.y < rowCount;
        //if (!ret) Debug.LogWarningFormat("Invalid coord: {0}", coord);
        return ret;
    }

    public CellInfo AddBlock(Vector2Int coord, Block block)
    {
        if (!IsValidCoord(coord)) return null;

        var stack = _stacks[coord.x, coord.y];
        if (stack == null)
        {
            stack = Instantiate(_stackPrefab, transform);
            stack.name = string.Concat("Stack", coord);
            stack.coord = coord;
            stack.onStackChanged = OnStackChanged;
            stack.onResChange = OnStackResChange;
            _stacks[coord.x, coord.y] = stack;
        }
        stack.Add(block);
        return Ground.instance.GetCellInfo(coord);
    }

    public BlockStack GetStack(Vector2Int coord)
    {
        if (!IsValidCoord(coord)) return null;
        return _stacks[coord.x, coord.y];
    }

    void OnStackChanged(BlockStack stack)
    {
        UpdateAliveBlockIds();
        var matrix = stack.GetMatrix();
        foreach (var s in matrix.all)
        {
            if (s != null) s.RequestCheckCombos();
        }
    }

    void OnStackResChange(IEnumerable<Res> deltaRes, BlockStack stack)
    {
        foreach (var res in deltaRes)
        {
            ResPopper.instance.Pop(res, stack);
            ResManager.instance.Add(res.id, res.amount);
        }
    }

    void UpdateAliveBlockIds()
    {
        _aliveBlockIds.Clear();
        for (int r = 0; r < rowCount; r++)
        {
            for (int c = 0; c < colCount; c++)
            {
                var s = _stacks[c, r];
                if (s == null) continue;
                var ids = _stacks[c, r].Select(b => b.id).Distinct();
                foreach (var id in ids)
                {
                    if (!_aliveBlockIds.ContainsKey(id)) _aliveBlockIds[id] = 0;
                    _aliveBlockIds[id]++;
                }
            }
        }
    }

    public int BlockCount(string id)
    {
        int count;
        if (!_aliveBlockIds.TryGetValue(id, out count)) return 0;
        return count;
    }

    #endregion

    [ContextMenu("Load Patterns")]
    public void LoadPatterns()
    {
        var a = Database.instance;
        Debug.Log(a.ToString());
    }
}
